package org.qianji.goosql.dql.clause;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.qianji.goosql.Fragment;
import org.qianji.goosql.field.Field;

/**
 * 排序子句。
 * 
 * @author gmz
 * 
 */
public class OrderBy implements Fragment {

	/**
	 * 
	 */
	private static final long serialVersionUID = 8259420195349779110L;

	private List<Order> orders = new ArrayList<Order>();

	/**
	 * 默认构造子。
	 */
	public OrderBy() {
		super();
	}

	/**
	 * 获取排序字段数。
	 * 
	 * @return {@link java.lang.Integer int} 排序字段数
	 */
	public int size() {
		return orders.size();
	}

	/**
	 * 添加排序字段。
	 * 
	 * @param field
	 *            {@link Field} 排序字段
	 * @param isAsc
	 *            {@link java.lang.Boolean} 是否升序，true-升序，false-降序
	 * @return {@link OrderBy} 分组子句
	 */
	public OrderBy addOrder(Field field, boolean isAsc) {
		if (field == null) {
			throw new NullPointerException("field can't be null");
		}
		Order od = new Order(field, isAsc);
		if (!orders.contains(od)) {
			orders.add(od);
		}
		return this;
	}

	@Override
	public String toSql() {
		StringBuffer ob = new StringBuffer("");
		int size = size();
		if (size > 0) {
			ob.append("ORDER BY ").append(orders.get(0).toSql());
			for (int i = 1; i < size; i++) {
				ob.append(",").append(orders.get(i).toSql());
			}
		}
		return ob.toString();
	}

	class Order implements Fragment {

		/**
		 * 
		 */
		private static final long serialVersionUID = 6190251802909098734L;

		private Field field;
		private boolean isAsc;

		public Order(Field field, boolean isAsc) {
			super();
			if (field == null) {
				throw new NullPointerException("field can't be null");
			}
			this.field = field;
			this.isAsc = isAsc;
		}

		public Field getField() {
			return field;
		}

		public boolean isAsc() {
			return isAsc;
		}

		@Override
		public String toSql() {
			StringBuffer od = new StringBuffer(field.toSql()).append(isAsc ? " ASC" : " DESC");
			return od.toString();
		}

		@Override
		public List<Object> getPlacedParameters() {
			return field.getPlacedParameters();
		}

		@Override
		public Map<String, Object> getNamedParameters() {
			return field.getNamedParameters();
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null || !(obj instanceof Order)) {
				return false;
			}
			Order other = (Order) obj;
			if (field.equals(other.getField()) && isAsc == other.isAsc) {
				return true;
			}
			return false;
		}

		@Override
		public int hashCode() {
			int hc = 37 * 17 + field.hashCode();
			hc = 37 * hc + (isAsc ? 1 : 0);
			return hc;
		}

		@Override
		public String toString() {
			return toSql();
		}

	}

	@Override
	public List<Object> getPlacedParameters() {
		List<Object> ppl = new ArrayList<Object>();
		if (size() > 0) {
			for (Order od : orders) {
				ppl.addAll(od.getPlacedParameters());
			}
		}
		return ppl;
	}

	@Override
	public Map<String, Object> getNamedParameters() {
		Map<String, Object> npm = new HashMap<String, Object>();
		if (size() > 0) {
			for (Order od : orders) {
				npm.putAll(od.getNamedParameters());
			}
		}
		return npm;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null || !(obj instanceof OrderBy)) {
			return false;
		}
		OrderBy other = (OrderBy) obj;
		if (size() == other.size()) {
			for (Order od : other.orders) {
				if (!orders.contains(od)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}

	@Override
	public int hashCode() {
		int hc = 17;
		for (Order od : orders) {
			hc = 37 * hc + od.hashCode();
		}
		return hc;
	}

	@Override
	public String toString() {
		return toSql();
	}

}
